#include <QtCore>
#include <QtGui>
#include "Network/XmlClient.hh"
#include "Network/XmlServer.hh"
#include "Test/ServerTest.hh"
#include "World/User.hh"
#include "Exception.hh"

int load_ssl_config(int argc, char* argv[], QString& key, QString& cert,
		QString& ca) {
	QString config = "ssl.conf";
	key = "";
	cert = "";
	ca = "";
	for (int i = 0; i < argc; i++) {
		if (!strcmp(argv[i],"-ssl-conf")) {
			config = argv[i+1];
			break;
		}
	}
//	qDebug("Using ssl config file: %s", config.toStdString().c_str());

	QFile file(config);
	if (!file.open(QIODevice::ReadOnly)) {
		qDebug("failed to load config file %s", config.toStdString().c_str());
		return -1;
	}

	QTextStream ts(&file);
	while (!ts.atEnd()) {
		QString id;
		QString tmp;
		ts >> id;
		ts >> tmp;
		ts.skipWhiteSpace();
		QString path = ts.readLine(255);

		bool check = false;
		if (!id.compare("key")) {
			key = path;
//			qDebug("key: %s", path.toStdString().c_str());
			check = true;
		} else if (!id.compare("certificate")) {
			cert = path;
//			qDebug("cert: %s", path.toStdString().c_str());
			check = true;
		} else if (!id.compare("ca")) {
			ca = path;
//			qDebug("ca: %s", path.toStdString().c_str());
			check = true;
		}
		if (check) {
			QFile tmp(path);
			if (!tmp.open(QIODevice::ReadOnly)) {
				qDebug("not found: %s", path.toStdString().c_str());
				exit(-1);
			}
			tmp.close();
		}
	}
	file.close();

	return 0;
}

int server_main(int argc, char* argv[], char* env[]) {
    DONTCARE(env);
    QCoreApplication app(argc, argv);
    // TODO ne legyen a felhasználó lista beledrótozva
//    World::User::construct("foo", "bar");
//    World::User::construct("bar", "baz");
//    World::User::construct("baz", "fuz");
//    World::User::construct("fuz", "foo");

    QString key;
    QString certificate;
    QString ca;

    load_ssl_config(argc, argv, key, certificate, ca);

    uint16_t port = DEFAULT_PORT;

    if (argc >= 1) {
        bool convOk = false;
        port = QString(argv[0]).toUShort(&convOk);

        if (!convOk) {
            qDebug("invalid port, falling back to %d", DEFAULT_PORT);
            port = DEFAULT_PORT;
        }
    }

    Network::XmlServer::instance().start(port, key, certificate, ca);
    int result = app.exec();
    qDebug("done");
    return result;
}

int client_main(int argc, char* argv[], char* env[]) {
    DONTCARE(env);
    QApplication app(argc, argv);

    QString key;
    QString certificate;
    QString ca;

    load_ssl_config(argc, argv, key, certificate, ca);

    qDebug("staring client");
    Network::XmlClient::instance().ssl_config(key, certificate, ca);
    Network::XmlClient::instance().start();
    int result = app.exec();
    qDebug("done");
    return result;
}

int test_main(int argc, char* argv[], char* env[]) {
    DONTCARE(env);
    QCoreApplication app(argc, argv);
    Test::ServerTest serverTest;
    return QTest::qExec(&serverTest, argc, argv);
}

/**
 * \brief A program belépési pontja.
 * \param argc A parancssori argumentumok száma.
 * \param argv A parancssori argumentumok tömbje.
 * \param env  A környezeti változók tömbje.
 * \return Sikeres volt-e a program futása.
 *
 * Elvégzi a parancssori argumentumok és környezeti változók részleges
 * értelmezését, létrehoz egy QApplication objektumot, és meghívja a
 * Main::main() statikus függvényt.
 */
int main(int argc, char* argv[], char* env[]) {
    QString arg = argv[0];

    if (arg == "lprog_server")
        return server_main(argc - 1, argv + 1, env);

    if (arg == "lprog_client")
        return client_main(argc - 1, argv + 1, env);

    if (arg == "lprog_test")
        return test_main(argc, argv + 1, env);

    if (argc >= 2) {
        arg = argv[1];

        if (arg == "s" || arg == "server")
            return server_main(argc - 2, argv + 2, env);

        if (arg == "c" || arg == "client")
            return client_main(argc - 2, argv + 2, env);

        if (arg == "t" || arg == "test")
            return test_main(argc - 1, argv + 1, env);
    } else {
        return server_main(argc - 1, argv + 1, env);
    }

    qDebug("terminating");
    return 1;
}
